#ifndef __TABLE2_H__
#define __TABLE2_H__

#include "yid.h"
#include "lich_id.h"
#include "table_proto.h"
#include "fileinfo.h"
#include "fs_proto.h"
#include "chunk.h"
#include "plock.h"
#include "chunk_proto.h"
#include "volume_proto_eclog.h"
#include "cluster.h"
#include "lease.h"

#include "lich_ctx.h"
#include "lsv.h"
#include "token_bucket.h"
#include "lichstor.h"
#include "lock_table.h"
#include "profile.h"


#pragma pack(8)

/**
 * 内存的table2，只有一个实例: volume_proto->table2
 * 通过该实例调用table2的操作，同时管理raw chunk的chunk info
 */

// #define TAB2_LOCK_ARRAY

typedef struct {
        io_t io;
        buffer_t buf;
        chkinfo_t *chkinfo;
        chkstat_t *chkstat;
        vfm_t *vfm;
        char __chkinfo__[CHKINFO_MAX];
        char __chkstat__[CHKSTAT_MAX];
        char __vfm__[VFM_SIZE(VFM_COUNT_MAX)];
} chunk_io_t;

/*table2*/
typedef struct __table2 {
        uint32_t chknum;

        plock_t rwlock; // for chunk_array & chkstat_array update
        // 目前分配的最大raw chunk数，数组内每项对应一个raw的chunk info
        chkinfo_t **chunk_array;
        chkstat_t **chkstat_array;

        //lock3.1 for each subvol operations, like load
        lock_table_t rwlock_sub;

        //lock3.2 for each chunk operations, like check,move,sync...
        lock_table_t rwlock_table;
        lock_table_t eclock_table; // for ec write

        // ltime=0，卷会重新加载
        time_t ltime;

        void *volume_proto;
        table1_t *table1;

        int (*chunk_create)(struct __table2 *table2, const chkid_t *chkid,
                            int chknum, io_opt_t *io_opt, void *volume_proto);
        int (*chunk_createwith)(struct __table2 *table2, const chkid_t *chkid, io_opt_t *io_opt, void *volume_proto,
                                const buffer_t *buf);

        // chunk_create的逆过程
        int (*chunk_discard)(struct __table2 *table2, const chkid_t *chkid, void *volume_proto);
        int (*chunk_batch_discard)(struct __table2 *table2, const chkid_t **chkid, int n_chks, void *volume_proto);

        int (*chunk_cleanup)(struct __table2 *, const chkid_t *chkid, const nid_t *_nid,
                             uint64_t meta_version, void *_volume_proto);

        int (*chunk_exist)(struct __table2 *table2, const chkid_t *chkid, int *exist, void *volume_proto);
        int (*chunk_getinfo)(struct __table2 *table2, const chkid_t *chkid, chkinfo_t *chkinfo);
        int (*chunk_stat)(struct __table2 *table2, const fileid_t *fileid,
                          const uint64_t *snap_rollback, filestat_t *stat, off_t off, size_t size);
        int (*chunk_iterator)(struct __table2 *, const fileid_t *fileid, func2_t func2, void *_arg, uint64_t idx);
        int (*chunk_unintact)(struct __table2 *, const fileid_t *fileid, func3_t func3, void *_arg, uint64_t idx, int deep);
        //int (*chunk_intact)(struct __table2 *table2, const chkid_t *chkid, int *intact);

        // 扩展chkinfo/chkstat数组
        int (*extend)(struct __table2 *table2, int idx, int op);//temporary

        // 设置某副本的状态
        int (*chunk_set)(struct __table2 *table2, const chkid_t *chkid,
                         const nid_t *nid, int status, void *volume_proto);

        // 检查各副本状态，必要时进行修复, async=1
        int (*chunk_check)(struct __table2 *table2, const chkid_t *chkid, int op,
                           int localize, uint64_t *snap_version, int *oflags);

        // 检查各副本状态，必要时进行修复, async=0
        int (*chunk_sync)(struct __table2 *table2, const chkid_t *chkid, int *oflags);

        // 设置chunk的副本集，回收多余的旧副本
        int (*chunk_move)(struct __table2 *table2, const chkid_t *chkid, const nid_t *nid, int count, void *volume_proto);

        // 确保卷控制器所在节点有一副本，必要时从别的节点move过来
        int (*chunk_localize)(struct __table2 *table2, const chkid_t *chkid, void *volume_proto);

        int (*chunk_snapshot_update)(struct __table2 *, const chkid_t *chkid, uint64_t snap_version, void *);

        int (*chunk_readzero)(struct __table2 *table2, chunk_io_t *chunk_io);
        int (*chunk_read)(struct __table2 *table2, chunk_io_t *chunk_io);
        int (*chunk_write)(struct __table2 *table2, chunk_io_t *chunk_io);
        
        int (*pre_io)(struct __table2 *table2, const chkid_t *chkid, chkinfo_t *_chkinfo,
                      chkstat_t *_chkstat, vfm_t *vfm, uint64_t *clock, int op);
        int (*reset)(struct __table2 *table2, const chkid_t *chkid);
        int (*post_io)(struct __table2 *table2, const chkid_t *chkid, const chkinfo_t *_chkinfo,
                       const chkstat_t *_chkstat, uint64_t clock);

        int (*load_bmap)(struct __table2 *table2, table_proto_t *table_proto);

        int (*vfm_set)(struct __table2 *table2, const chkid_t *chkid, const uint64_t *prev, const vfm_t *_vfm, int force);
        int (*vfm_set_dangerously)(struct __table2 *table2, const chkid_t *chkid, const vfm_t *_vfm);
        int (*vfm_add)(struct __table2 *table2, const chkid_t *chkid, const nid_t *nid, int count);
        int (*vfm_get)(struct __table2 *table2, const chkid_t *chkid, vfm_t *_vfm);

        int (*vfm_lock)(struct __table2 *table2, const chkid_t *chkid);
        int (*vfm_unlock)(struct __table2 *table2, const chkid_t *chkid);

        int (*vfm_cleanup)(struct __table2 *table2, const chkid_t *tid);

        // private
} table2_t;

/*

table1 / table2

@insert
@update
@check
@update_parent
@check_parent
@lock
*/

#pragma pack()

#endif
